/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.project.imported;

import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.dto.project.ImportConflictDTO;
import cn.ac.nercis.pes.model.standard.SystemEvaluationSDTO;
import cn.ac.nercis.pes.model.standard.SystemSDTO;
import cn.ac.nercis.pes.repository.dal.project.ProjectRepository;
import cn.ac.nercis.pes.repository.dal.project.SystemRepository;
import cn.ac.nercis.pes.repository.mapper.standard.SystemImportMapper;
import cn.ac.nercis.pes.repository.model.project.ProjectDO;
import cn.ac.nercis.pes.repository.model.project.SystemDO;
import cn.ac.nercis.pes.service.project.SystemEvaluationService;
import cn.ac.nercis.pes.service.utils.CheckFieldUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 系统基础数据导入服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public record SystemBaseImportService(ProjectRepository projectRepository,
                                      SystemRepository systemRepository,
                                      SystemEvaluationService systemEvaluationService) {
    @Autowired
    public SystemBaseImportService {
    }

    public Result<List<ImportConflictDTO>> checkSystemBaseData(@NonNull SystemSDTO importSystem, String selectSystemId) {
        var sourceSystem = systemRepository.findById(selectSystemId).orElse(null);;
        if (Objects.isNull(sourceSystem)) {
            return Result.failed("导入的数据系统不存在！");
        }
        if (!checkSecurityLevel(sourceSystem, importSystem)) {
            return Result.failed("导入的系统安全等级与对应系统不一致");
        }
        var systemEvaluation = systemEvaluationService.getSystemEvaluation(sourceSystem.getId());
        if(Objects.isNull(systemEvaluation)){
            return Result.failed("导入的被测信息系统基本信息不存在");
        }
        List<ImportConflictDTO> conflictData = CheckFieldUtils.checkField(sourceSystem, importSystem);
        conflictData.addAll(CheckFieldUtils.checkField(systemEvaluation, importSystem.getEvaluation()));
        return Result.success(conflictData);
    }

    public Result<String> importSystemBaseData(@NonNull SystemSDTO importSystem, String selectSystemId, @NonNull Boolean cover) {
        var sourceSystem = systemRepository.findById(selectSystemId).orElse(null);
        if (Objects.isNull(sourceSystem)) {
            return Result.failed("导入的数据系统不存在！");
        } else {
            return modifySystemBaseData(sourceSystem, importSystem, cover);
        }
    }

    private SystemDO getSystemDO(String projectId, String importSystemName, String selectSystemId){
        if(StringUtils.isNotBlank(selectSystemId)){
            return systemRepository.findById(selectSystemId).orElse(null);
        }
        return systemRepository.findAllByProjectId(projectId)
                .stream()
                .filter(s -> StringUtils.equals(s.getName(), importSystemName))
                .findFirst()
                .orElse(null);
    }

    private Result<String> createSystemBaseData(String projectId, SystemSDTO importSystem) {
        ProjectDO projectDO = this.projectRepository.findById(projectId).orElse(null);
        if (Objects.isNull(projectDO)) {
            return Result.failed(ResultCode.PROJECT_NOT_EXIST);
        }
        SystemDO systemDO = SystemImportMapper.INSTANCE.toDO(importSystem);
        systemDO.setId("");
        systemDO.setProject(projectDO);
        systemDO.setCreateTime(LocalDateTime.now());
        systemDO.setModifyTime(LocalDateTime.now());
        return Optional.of(systemDO)
                .map(this.systemRepository::save)
                .map(entity->{
                    systemEvaluationService.initSystemEvaluation(entity,SystemImportMapper.INSTANCE.toDO(importSystem.getEvaluation()));
                    return entity.getId();
                })
                .map(Result::success)
                .orElse(Result.failed("系统基础信息创建失败"));
    }

    private Result<String> modifySystemBaseData(SystemDO sourceSystem, SystemSDTO importSystem, Boolean cover) {
        sourceSystem.setIsFiling(CheckFieldUtils.applyContent(sourceSystem.getIsFiling(), importSystem.getIsFiling(), cover));
        sourceSystem.setFilingNumber(CheckFieldUtils.applyContent(sourceSystem.getFilingNumber(), importSystem.getFilingNumber(), cover));
        sourceSystem.setState(CheckFieldUtils.applyContent(sourceSystem.getState(), importSystem.getState(), cover));
        sourceSystem.setFinishDate(CheckFieldUtils.applyContent(sourceSystem.getFinishDate(), importSystem.getFinishDate(), cover));
        sourceSystem.setDecision(CheckFieldUtils.applyContent(sourceSystem.getDecision(), importSystem.getDecision(), cover));
        sourceSystem.setDesc(CheckFieldUtils.applyContent(sourceSystem.getDesc(), importSystem.getDesc(), cover));
        var evaluationDO = systemEvaluationService.getSystemEvaluation(sourceSystem.getId());
        if (Objects.isNull(evaluationDO)) {
            evaluationDO = SystemImportMapper.INSTANCE.toDO(importSystem.getEvaluation());
            evaluationDO.setSystemId(sourceSystem.getId());
            sourceSystem.setCreateTime(LocalDateTime.now());
            sourceSystem.setModifyTime(LocalDateTime.now());
        } else {
            SystemEvaluationSDTO evaluationSDTO = importSystem.getEvaluation();
            evaluationDO.setIsChange(CheckFieldUtils.applyContent(evaluationDO.getIsChange(), evaluationSDTO.getIsChange(), cover));
            evaluationDO.setChangeDesc(CheckFieldUtils.applyContent(evaluationDO.getChangeDesc(), evaluationSDTO.getChangeDesc(), cover));


            evaluationDO.setCiiState(CheckFieldUtils.applyContent(evaluationDO.getCiiState(), evaluationSDTO.getCiiState(), true));
            evaluationDO.setCiiDesc(CheckFieldUtils.applyContent(evaluationDO.getCiiDesc(), evaluationSDTO.getCiiDesc(), true));

            evaluationDO.setGradeProtectionState(CheckFieldUtils.applyContent(evaluationDO.getGradeProtectionState(), evaluationSDTO.getGradeProtectionState(), cover));
            evaluationDO.setEvaluationUnitName(CheckFieldUtils.applyContent(evaluationDO.getEvaluationUnitName(), evaluationSDTO.getEvaluationUnitName(), cover));
            evaluationDO.setEvaluationDate(CheckFieldUtils.applyContent(evaluationDO.getEvaluationDate(), evaluationSDTO.getEvaluationDate(), cover));

            evaluationDO.setConclusion(CheckFieldUtils.applyContent(evaluationDO.getConclusion(), evaluationSDTO.getConclusion(), cover));

            evaluationDO.setServiceRange(CheckFieldUtils.applyContent(evaluationDO.getServiceRange(), evaluationSDTO.getServiceRange(), cover));
            evaluationDO.setInterProvincialCount(CheckFieldUtils.applyContent(evaluationDO.getInterProvincialCount(), evaluationSDTO.getInterProvincialCount(), cover));
            evaluationDO.setInterAreaCount(CheckFieldUtils.applyContent(evaluationDO.getInterAreaCount(), evaluationSDTO.getInterAreaCount(), cover));
            evaluationDO.setServiceRangeDesc(CheckFieldUtils.applyContent(evaluationDO.getServiceRangeDesc(), evaluationSDTO.getServiceRangeDesc(), cover));
            evaluationDO.setServiceScope(CheckFieldUtils.applyContent(evaluationDO.getServiceScope(), evaluationSDTO.getServiceScope(), cover));
            evaluationDO.setServiceScopeDesc(CheckFieldUtils.applyContent(evaluationDO.getServiceScopeDesc(), evaluationSDTO.getServiceScopeDesc(), cover));
            evaluationDO.setServiceObject(CheckFieldUtils.applyContent(evaluationDO.getServiceObject(), evaluationSDTO.getServiceObject(), cover));
            evaluationDO.setServiceObjectDesc(CheckFieldUtils.applyContent(evaluationDO.getServiceObjectDesc(), evaluationSDTO.getServiceObjectDesc(), cover));

            evaluationDO.setCoverage(CheckFieldUtils.applyContent(evaluationDO.getCoverage(), evaluationSDTO.getCoverage(), cover));
            evaluationDO.setCoverageDesc(CheckFieldUtils.applyContent(evaluationDO.getCoverageDesc(), evaluationSDTO.getCoverageDesc(), cover));
            evaluationDO.setNetworkNature(CheckFieldUtils.applyContent(evaluationDO.getNetworkNature(), evaluationSDTO.getNetworkNature(), cover));
            evaluationDO.setNetworkNatureDesc(CheckFieldUtils.applyContent(evaluationDO.getNetworkNatureDesc(), evaluationSDTO.getNetworkNatureDesc(), cover));

            evaluationDO.setServiceUserCount(CheckFieldUtils.applyContent(evaluationDO.getServiceUserCount(), evaluationSDTO.getServiceUserCount(), cover));
            evaluationDO.setIsRunning(CheckFieldUtils.applyContent(evaluationDO.getIsRunning(), evaluationSDTO.getIsRunning(), cover));
            evaluationDO.setRunYear(CheckFieldUtils.applyContent(evaluationDO.getRunYear(), evaluationSDTO.getRunYear(), cover));
            evaluationDO.setRunMonth(CheckFieldUtils.applyContent(evaluationDO.getRunMonth(), evaluationSDTO.getRunMonth(), cover));
            evaluationDO.setRunDesc(CheckFieldUtils.applyContent(evaluationDO.getRunDesc(), evaluationSDTO.getRunDesc(), cover));

            evaluationDO.setInterconnection(CheckFieldUtils.applyContent(evaluationDO.getInterconnection(), evaluationSDTO.getInterconnection(), cover));
            evaluationDO.setInterconnectionDesc(CheckFieldUtils.applyContent(evaluationDO.getInterconnectionDesc(), evaluationSDTO.getInterconnectionDesc(), cover));
            evaluationDO.setNetName(CheckFieldUtils.applyContent(evaluationDO.getNetName(), evaluationSDTO.getNetName(), true));

            evaluationDO.setCloudState(CheckFieldUtils.applyContent(evaluationDO.getCloudState(), evaluationSDTO.getCloudState(), true));
            evaluationDO.setCloudName(CheckFieldUtils.applyContent(evaluationDO.getCloudName(), evaluationSDTO.getCloudName(), true));
            evaluationDO.setCloudSelectState(CheckFieldUtils.applyContent(evaluationDO.getCloudSelectState(), evaluationSDTO.getCloudSelectState(), true));
            evaluationDO.setCloudUnit(CheckFieldUtils.applyContent(evaluationDO.getCloudUnit(), evaluationSDTO.getCloudUnit(), true));
            evaluationDO.setCloudDate(CheckFieldUtils.applyContent(evaluationDO.getCloudDate(), evaluationSDTO.getCloudDate(), true));
            evaluationDO.setCloudCon(CheckFieldUtils.applyContent(evaluationDO.getCloudCon(), evaluationSDTO.getCloudCon(), true));

            evaluationDO.setPaScheme(CheckFieldUtils.applyContent(evaluationDO.getPaScheme(), evaluationSDTO.getPaScheme(), cover));
            evaluationDO.setPassDate(CheckFieldUtils.applyContent(evaluationDO.getPassDate(), evaluationSDTO.getPassDate(), cover));
            evaluationDO.setPaSchemeMethod(CheckFieldUtils.applyContent(evaluationDO.getPaSchemeMethod(), evaluationSDTO.getPaSchemeMethod(), cover));
            evaluationDO.setPaSchemeUnit(CheckFieldUtils.applyContent(evaluationDO.getPaSchemeUnit(), evaluationSDTO.getPaSchemeUnit(), cover));

            evaluationDO.setPpSituation(CheckFieldUtils.applyContent(evaluationDO.getPpSituation(), evaluationSDTO.getPpSituation(), cover));
            evaluationDO.setPpSituationCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationCount(), evaluationSDTO.getPpSituationCount(), cover));
            evaluationDO.setPpSituationIndependentCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationIndependentCount(), evaluationSDTO.getPpSituationIndependentCount(), cover));
            evaluationDO.setPpSituationSharedCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationSharedCount(), evaluationSDTO.getPpSituationSharedCount(), cover));
            evaluationDO.setPpSituationCertifiedCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationCertifiedCount(), evaluationSDTO.getPpSituationCertifiedCount(), cover));
            evaluationDO.setPpSituationUnCertifiedCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationUnCertifiedCount(), evaluationSDTO.getPpSituationUnCertifiedCount(), cover));
            evaluationDO.setPpSituationForeignCount(CheckFieldUtils.applyContent(evaluationDO.getPpSituationForeignCount(), evaluationSDTO.getPpSituationForeignCount(), cover));

            evaluationDO.setGroupingAlgorithm(CheckFieldUtils.applyContent(evaluationDO.getGroupingAlgorithm(), evaluationSDTO.getGroupingAlgorithm(), cover));
            evaluationDO.setGroupingAlgorithmDesc(CheckFieldUtils.applyContent(evaluationDO.getGroupingAlgorithmDesc(), evaluationSDTO.getGroupingAlgorithmDesc(), cover));
            evaluationDO.setAsymmetricAlgorithm(CheckFieldUtils.applyContent(evaluationDO.getAsymmetricAlgorithm(), evaluationSDTO.getAsymmetricAlgorithm(), cover));
            evaluationDO.setAsymmetricAlgorithmDesc(CheckFieldUtils.applyContent(evaluationDO.getAsymmetricAlgorithmDesc(), evaluationSDTO.getAsymmetricAlgorithmDesc(), cover));
            evaluationDO.setHashAlgorithm(CheckFieldUtils.applyContent(evaluationDO.getHashAlgorithm(), evaluationSDTO.getHashAlgorithm(), cover));
            evaluationDO.setHashAlgorithmDesc(CheckFieldUtils.applyContent(evaluationDO.getHashAlgorithmDesc(), evaluationSDTO.getHashAlgorithmDesc(), cover));
            evaluationDO.setSequenceAlgorithm(CheckFieldUtils.applyContent(evaluationDO.getSequenceAlgorithm(), evaluationSDTO.getSequenceAlgorithm(), cover));
            evaluationDO.setSequenceAlgorithmDesc(CheckFieldUtils.applyContent(evaluationDO.getSequenceAlgorithmDesc(), evaluationSDTO.getSequenceAlgorithmDesc(), cover));
            evaluationDO.setOtherAlgorithmDesc(CheckFieldUtils.applyContent(evaluationDO.getOtherAlgorithmDesc(), evaluationSDTO.getOtherAlgorithmDesc(), cover));

            evaluationDO.setModifyTime(LocalDateTime.now());
        }
        var evaluationResult = systemEvaluationService.save(sourceSystem.getId(),evaluationDO);
        if(!evaluationResult.isSuccess()){
            return Result.failed("系统测评基础信息修改失败");
        }
        return Optional.of(sourceSystem)
                .map(this.systemRepository::save)
                .map(SystemDO::getId)
                .map(Result::success)
                .orElse(Result.failed("系统基础信息修改失败"));
    }

    private boolean checkSecurityLevel(SystemDO sourceSystem, SystemSDTO importSystem) {
        return sourceSystem.getSecurityLevel() == importSystem.getSecurityLevel();
    }

}
